#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
应用程序配置文件

这个文件包含了应用程序的所有配置设置，包括：
1. 数据库连接配置
2. 安全设置
3. 服务器配置
4. 第三方服务配置

使用 Pydantic Settings 进行配置管理，支持环境变量覆盖

作者: FastAPI 学习项目
创建时间: 2024
"""

import os
from typing import List, Optional
from pydantic import validator
from pydantic_settings import BaseSettings
from functools import lru_cache


class Settings(BaseSettings):
    """
    应用程序设置类
    
    使用 Pydantic BaseSettings 自动从环境变量加载配置
    支持类型验证和默认值设置
    """
    
    # 应用程序基本设置
    APP_NAME: str = "FastAPI 学习项目"
    APP_VERSION: str = "1.0.0"
    DEBUG: bool = True
    
    # 服务器配置
    HOST: str = "127.0.0.1"
    PORT: int = 8000
    
    # 安全配置
    SECRET_KEY: str = "your-secret-key-change-this-in-production"
    ALGORITHM: str = "HS256"
    ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
    REFRESH_TOKEN_EXPIRE_DAYS: int = 7
    
    # 数据库配置
    DATABASE_URL: str = "sqlite:///./fastapi_learning.db"
    DATABASE_ECHO: bool = False  # 是否打印 SQL 语句
    
    # PostgreSQL 配置（可选）
    POSTGRES_USER: Optional[str] = None
    POSTGRES_PASSWORD: Optional[str] = None
    POSTGRES_HOST: Optional[str] = None
    POSTGRES_PORT: Optional[int] = 5432
    POSTGRES_DB: Optional[str] = None
    
    # Redis 配置（可选）
    REDIS_URL: str = "redis://localhost:6379/0"
    REDIS_EXPIRE_TIME: int = 3600  # 缓存过期时间（秒）
    
    # CORS 配置
    ALLOWED_HOSTS: List[str] = ["*"]
    
    # 文件上传配置
    MAX_FILE_SIZE: int = 10 * 1024 * 1024  # 10MB
    ALLOWED_FILE_TYPES: List[str] = [
        "image/jpeg",
        "image/png",
        "image/gif",
        "application/pdf",
        "text/plain"
    ]
    UPLOAD_DIR: str = "./uploads"
    
    # 日志配置
    LOG_LEVEL: str = "INFO"
    LOG_FILE: str = "./logs/app.log"
    
    # 邮件配置（可选）
    SMTP_HOST: Optional[str] = None
    SMTP_PORT: Optional[int] = 587
    SMTP_USER: Optional[str] = None
    SMTP_PASSWORD: Optional[str] = None
    SMTP_TLS: bool = True
    
    # API 限流配置
    RATE_LIMIT_PER_MINUTE: int = 60
    
    # 分页配置
    DEFAULT_PAGE_SIZE: int = 20
    MAX_PAGE_SIZE: int = 100
    
    @validator("SECRET_KEY")
    def validate_secret_key(cls, v):
        """
        验证密钥长度
        
        Args:
            v: 密钥值
            
        Returns:
            str: 验证后的密钥
            
        Raises:
            ValueError: 当密钥长度不足时抛出异常
        """
        if len(v) < 32:
            raise ValueError("SECRET_KEY 长度必须至少为 32 个字符")
        return v
    
    @validator("DATABASE_URL")
    def validate_database_url(cls, v):
        """
        验证数据库 URL 格式
        
        Args:
            v: 数据库 URL
            
        Returns:
            str: 验证后的数据库 URL
        """
        if not v.startswith(("sqlite://", "postgresql://", "mysql://")):
            raise ValueError("不支持的数据库类型")
        return v
    
    @property
    def postgres_url(self) -> Optional[str]:
        """
        构建 PostgreSQL 连接 URL
        
        Returns:
            Optional[str]: PostgreSQL 连接字符串，如果配置不完整则返回 None
        """
        if all([
            self.POSTGRES_USER,
            self.POSTGRES_PASSWORD,
            self.POSTGRES_HOST,
            self.POSTGRES_DB
        ]):
            return (
                f"postgresql://{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}"
                f"@{self.POSTGRES_HOST}:{self.POSTGRES_PORT}/{self.POSTGRES_DB}"
            )
        return None
    
    def get_database_url(self) -> str:
        """
        获取实际使用的数据库 URL
        
        优先使用 PostgreSQL，如果配置不完整则使用 SQLite
        
        Returns:
            str: 数据库连接字符串
        """
        postgres_url = self.postgres_url
        if postgres_url:
            return postgres_url
        return self.DATABASE_URL
    
    class Config:
        """
        Pydantic 配置类
        
        指定环境变量文件和其他配置选项
        """
        env_file = ".env"
        env_file_encoding = "utf-8"
        case_sensitive = True


@lru_cache()
def get_settings() -> Settings:
    """
    获取应用程序设置实例
    
    使用 lru_cache 装饰器确保设置对象只创建一次
    这是一个常见的单例模式实现
    
    Returns:
        Settings: 应用程序设置实例
    """
    return Settings()


# 创建全局设置实例
settings = get_settings()


# 开发环境配置
class DevelopmentSettings(Settings):
    """
    开发环境特定配置
    
    继承基础设置并覆盖开发环境相关的配置
    """
    DEBUG: bool = True
    DATABASE_ECHO: bool = True
    LOG_LEVEL: str = "DEBUG"


# 生产环境配置
class ProductionSettings(Settings):
    """
    生产环境特定配置
    
    继承基础设置并覆盖生产环境相关的配置
    """
    DEBUG: bool = False
    DATABASE_ECHO: bool = False
    LOG_LEVEL: str = "WARNING"
    ALLOWED_HOSTS: List[str] = ["yourdomain.com", "www.yourdomain.com"]


# 测试环境配置
class TestSettings(Settings):
    """
    测试环境特定配置
    
    继承基础设置并覆盖测试环境相关的配置
    """
    DATABASE_URL: str = "sqlite:///./test.db"
    SECRET_KEY: str = "test-secret-key-for-testing-only-32-chars"
    ACCESS_TOKEN_EXPIRE_MINUTES: int = 5


def get_settings_by_env(env: str = None) -> Settings:
    """
    根据环境变量获取对应的设置实例
    
    Args:
        env: 环境名称 (development, production, testing)
        
    Returns:
        Settings: 对应环境的设置实例
    """
    if env is None:
        env = os.getenv("ENVIRONMENT", "development")
    
    if env == "production":
        return ProductionSettings()
    elif env == "testing":
        return TestSettings()
    else:
        return DevelopmentSettings()


# 导出常用配置
__all__ = [
    "Settings",
    "DevelopmentSettings",
    "ProductionSettings",
    "TestSettings",
    "get_settings",
    "get_settings_by_env",
    "settings"
]